{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 数学函数"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "**将数组a中大于30的值替换为30，小于10的值替换为10。**\n",
    "\n",
    "- `a = np.random.uniform(1, 50, 20)`\n",
    "\n",
    "【知识点：数学函数、搜索】\n",
    "- 如何将大于给定值的所有值替换为给定的截止值？"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2020-09-06T03:08:51.850958Z",
     "start_time": "2020-09-06T03:08:51.759473Z"
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "[27.63 14.64 21.8  42.39  1.23  6.96 33.87 41.47  7.7  29.18 44.67 11.25\n",
      " 10.08  6.31 11.77 48.95 40.77  9.43 41.   14.43]\n",
      "[27.63 14.64 21.8  30.   10.   10.   30.   30.   10.   29.18 30.   11.25\n",
      " 10.08 10.   11.77 30.   30.   10.   30.   14.43]\n",
      "[27.63 14.64 21.8  30.   10.   10.   30.   30.   10.   29.18 30.   11.25\n",
      " 10.08 10.   11.77 30.   30.   10.   30.   14.43]\n"
     ]
    }
   ],
   "source": [
    "import numpy as np\n",
    "\n",
    "np.set_printoptions(precision=2)\n",
    "np.random.seed(100)\n",
    "a = np.random.uniform(1, 50, 20)\n",
    "print(a)\n",
    "# [27.63 14.64 21.8  42.39  1.23  6.96 33.87 41.47  7.7  29.18 44.67 11.25\n",
    "#  10.08  6.31 11.77 48.95 40.77  9.43 41.   14.43]\n",
    "\n",
    "# 方法1\n",
    "b = np.clip(a, a_min=10, a_max=30)\n",
    "print(b)\n",
    "# [27.63 14.64 21.8  30.   10.   10.   30.   30.   10.   29.18 30.   11.25\n",
    "#  10.08 10.   11.77 30.   30.   10.   30.   14.43]\n",
    "\n",
    "# 方法2\n",
    "b = np.where(a < 10, 10, a)\n",
    "b = np.where(b > 30, 30, b)\n",
    "print(b)\n",
    "# [27.63 14.64 21.8  30.   10.   10.   30.   30.   10.   29.18 30.   11.25\n",
    "#  10.08 10.   11.77 30.   30.   10.   30.   14.43]"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "ExecuteTime": {
     "end_time": "2020-09-06T03:21:06.830747Z",
     "start_time": "2020-09-06T03:21:06.825756Z"
    }
   },
   "source": [
    "\n",
    "**找到一个一维数字数组a中的所有峰值。峰顶是两边被较小数值包围的点。**\n",
    "\n",
    "- `a = np.array([1, 3, 7, 1, 2, 6, 0, 1])`\n",
    "\n",
    "【知识点：数学函数、搜索】\n",
    "- 如何在一维数组中找到所有的局部极大值（或峰值）？"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2020-09-06T03:21:25.424045Z",
     "start_time": "2020-09-06T03:21:25.417035Z"
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "[ 2  4 -6  1  4 -6  1]\n",
      "[ 1  1 -1  1  1 -1  1]\n",
      "[ 0 -2  2  0 -2  2]\n",
      "[2 5]\n"
     ]
    }
   ],
   "source": [
    "import numpy as np\n",
    "\n",
    "a = np.array([1, 3, 7, 1, 2, 6, 0, 1])\n",
    "b1 = np.diff(a)\n",
    "b2 = np.sign(b1)\n",
    "b3 = np.diff(b2)\n",
    "\n",
    "print(b1)  # [ 2  4 -6  1  4 -6  1]\n",
    "print(b2)  # [ 1  1 -1  1  1 -1  1]\n",
    "print(b3)  # [ 0 -2  2  0 -2  2]\n",
    "index = np.where(np.equal(b3, -2))[0] + 1\n",
    "print(index) # [2 5]"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "**对于给定的一维数组，计算窗口大小为3的移动平均值。**\n",
    "\n",
    "- `z = np.random.randint(10, size=10)`\n",
    "\n",
    "【知识点：数学函数】\n",
    "- 如何计算numpy数组的移动平均值？"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 8,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2020-09-06T03:23:59.067424Z",
     "start_time": "2020-09-06T03:23:59.062437Z"
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "[8 8 3 7 7 0 4 2 5 2]\n",
      "[6.33 6.   5.67 4.67 3.67 2.   3.67 3.  ]\n"
     ]
    }
   ],
   "source": [
    "import numpy as np\n",
    "\n",
    "np.random.seed(100)\n",
    "z = np.random.randint(10, size=10)\n",
    "print(z)\n",
    "# [8 8 3 7 7 0 4 2 5 2]\n",
    "\n",
    "def MovingAverage(arr, n=3):\n",
    "    a = np.cumsum(arr)\n",
    "    a[n:] = a[n:] - a[:-n]\n",
    "    return a[n - 1:] / n\n",
    "\n",
    "\n",
    "r = MovingAverage(z, 3)\n",
    "print(np.around(r, 2))\n",
    "# [6.33 6.   5.67 4.67 3.67 2.   3.67 3.  ]"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "ExecuteTime": {
     "end_time": "2020-09-14T09:26:27.187954Z",
     "start_time": "2020-09-14T09:26:27.183972Z"
    }
   },
   "source": [
    "**对一个5x5的随机矩阵做归一化**\n",
    "\n",
    "【知识点：数学函数】\n",
    "- (提示: (x - min) / (max - min))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2020-09-14T09:26:59.520324Z",
     "start_time": "2020-09-14T09:26:59.515666Z"
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "[[0.65852707 0.23160203 0.9700425  0.43393441 0.36950354]\n",
      " [0.58585632 0.01877358 0.         0.27782335 0.89654906]\n",
      " [0.71307774 0.32030221 0.55187887 0.01411576 0.38903753]\n",
      " [0.05702349 0.40824762 0.23277188 0.74335934 0.72125366]\n",
      " [0.59816442 0.98727663 1.         0.86466287 0.42760849]]\n"
     ]
    }
   ],
   "source": [
    "Z = np.random.random((5,5))\n",
    "Zmax, Zmin = Z.max(), Z.min()\n",
    "Z = (Z - Zmin)/(Zmax - Zmin)\n",
    "print(Z)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "**用五种不同的方法去提取一个随机数组的整数部分**\n",
    "\n",
    "【知识点：数学函数】\n",
    "\n",
    "- (提示: %, np.floor, np.ceil, astype, np.trunc)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2020-09-14T09:31:37.950320Z",
     "start_time": "2020-09-14T09:31:37.944304Z"
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "[8. 5. 5. 1. 2. 7. 0. 1. 5. 9.]\n",
      "[8. 5. 5. 1. 2. 7. 0. 1. 5. 9.]\n",
      "[8. 5. 5. 1. 2. 7. 0. 1. 5. 9.]\n",
      "[8 5 5 1 2 7 0 1 5 9]\n",
      "[8. 5. 5. 1. 2. 7. 0. 1. 5. 9.]\n"
     ]
    }
   ],
   "source": [
    "Z = np.random.uniform(0,10,10)\n",
    "\n",
    "print (Z - Z%1)\n",
    "print (np.floor(Z))\n",
    "print (np.ceil(Z)-1)\n",
    "print (Z.astype(int))\n",
    "print (np.trunc(Z))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "**考虑一维数组Z，构建一个二维数组，其第一行为（Z [0]，Z [1]，Z [2]），随后的每一行都移位1（最后一行应为（Z [ -3]，Z [-2]，Z [-1]）**\n",
    "\n",
    "【知识点：数学函数】\n",
    "\n",
    "- （提示np.lib.stride_tricks）"
   ]
  },
  {
   "attachments": {
    "image.png": {
     "image/png": "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"
    }
   },
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]--------> ![image.png](attachment:image.png)     "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 8,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2020-09-14T13:38:56.805424Z",
     "start_time": "2020-09-14T13:38:56.800436Z"
    }
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "4"
      ]
     },
     "execution_count": 8,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "np.arange(10).itemsize"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2020-09-14T13:32:50.080815Z",
     "start_time": "2020-09-14T13:32:49.737937Z"
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "[[0 1 2]\n",
      " [1 2 3]\n",
      " [2 3 4]\n",
      " [3 4 5]\n",
      " [4 5 6]\n",
      " [5 6 7]\n",
      " [6 7 8]\n",
      " [7 8 9]]\n"
     ]
    }
   ],
   "source": [
    "from numpy.lib import stride_tricks\n",
    "def rolling(a, window):\n",
    "    shape = (a.size - window + 1, window)\n",
    "    strides = (a.itemsize, a.itemsize)\n",
    "    return stride_tricks.as_strided(a, shape=shape, strides=strides)\n",
    "Z = rolling(np.arange(10), 3)\n",
    "print (Z)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "**考虑两组点集P0和P1去描述一组线(二维)和一个点p,如何计算点p到每一条线 i (P0[i],P1[i])的距离？**\n",
    "\n",
    "【知识点：数学函数】\n",
    "- 提示 设P(x0,y0)，直线方程为：Ax+By+C=0\n",
    "则P到直线的距离为:d=|Ax0+By0+C|/√(A²+B²)\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 50,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2020-09-15T05:37:30.811695Z",
     "start_time": "2020-09-15T05:37:30.805709Z"
    }
   },
   "outputs": [],
   "source": [
    "import numpy as np\n",
    "def distance(P0,P1,p):\n",
    "    A=-1/(P1[:,0]-P0[:,0])\n",
    "    B=1/(P1[:,1]-P0[:,1])\n",
    "    C=P0[:,0]/(P1[:,0]-P0[:,0])-P0[:,1]/(P1[:,1]-P0[:,1])\n",
    "    return np.abs(A*p[:,0]+B*p[:,1]+C)/np.sqrt(A**2+B**2)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 51,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2020-09-15T05:37:37.692332Z",
     "start_time": "2020-09-15T05:37:37.687379Z"
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "[ 2.41120585  7.05924485  5.94906338  3.89096895  7.68364539 14.01851392\n",
      "  4.28148124  2.29582076  6.19155339 15.55087594]\n"
     ]
    }
   ],
   "source": [
    "P0 = np.random.uniform(-10,10,(10,2))\n",
    "P1 = np.random.uniform(-10,10,(10,2))\n",
    "p  = np.random.uniform(-10,10,( 1,2))\n",
    "\n",
    "print (distance(P0, P1, p))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    " **画正弦函数和余弦函数， x = np.arange(0, 3 * np.pi, 0.1)？**"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "[<matplotlib.lines.Line2D at 0x236a41aac88>]"
      ]
     },
     "execution_count": 4,
     "metadata": {},
     "output_type": "execute_result"
    },
    {
     "data": {
      "image/png": "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\n",
      "text/plain": [
       "<Figure size 432x288 with 1 Axes>"
      ]
     },
     "metadata": {
      "needs_background": "light"
     },
     "output_type": "display_data"
    }
   ],
   "source": [
    "import numpy as np\n",
    "from matplotlib import pyplot as plt\n",
    "x = np.arange(0, 3*np.pi, 0.1)\n",
    "y1 = np.sin(x)\n",
    "y2 = np.cos(x)\n",
    "plt.plot(x, y1)\n",
    "plt.plot(x, y2)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "**减去矩阵每一行的平均值 ？**"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "[[-0.22611265  0.18681928  0.13113673 -0.42713648  0.13273158  0.01160406\n",
      "   0.54266804 -0.15637426  0.16445073 -0.35978702]\n",
      " [-0.34359842  0.26798252  0.35328871  0.40386463 -0.45020099  0.40738698\n",
      "   0.10061077 -0.32664784  0.1162996  -0.52898595]\n",
      " [ 0.08892378 -0.10264121  0.27575287 -0.00792712  0.01868823  0.18782665\n",
      "   0.00795426 -0.12014542 -0.35177329  0.00334125]\n",
      " [-0.46156881 -0.40474198  0.15298977  0.17155644  0.17332436 -0.06791347\n",
      "  -0.12123457  0.00349192  0.28866751  0.26542884]\n",
      " [-0.39891856 -0.01008639  0.50523343 -0.28914192  0.01382436 -0.15406104\n",
      "  -0.22350635  0.45768516 -0.17832199  0.2772933 ]]\n"
     ]
    }
   ],
   "source": [
    "X = np.random.rand(5, 10)\n",
    "# 新\n",
    "Y = X - X.mean(axis=1, keepdims=True)\n",
    "# 旧\n",
    "Y = X - X.mean(axis=1).reshape(-1, 1)\n",
    "print(Y)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "**进行概率统计分析 ？**\n",
    "- `arr1 = np.random.randint(1,10,10)\n",
    "arr2 = np.random.randint(1,10,10))`"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "f\n",
    "arr1 = np.random.randint(1,10,10)\n",
    "arr2 = np.random.randint(1,10,10)\n",
    "\n",
    "print(\"arr1的平均数为:%s\" %np.mean(arr1))\n",
    "print(\"arr1的中位数为:%s\" %np.median(arr1))\n",
    "print(\"arr1的方差为:%s\" %np.var(arr1))\n",
    "print(\"arr1的标准差为:%s\" %np.std(arr1))\n",
    "print(\"arr1,arr的相关性矩阵为:%s\" %np.cov(arr1,arr2))\n",
    "print(\"arr1,arr的协方差矩阵为:%s\" %np.corrcoef(arr1,arr2))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "ExecuteTime": {
     "end_time": "2020-09-06T02:33:06.525406Z",
     "start_time": "2020-09-06T02:33:06.520453Z"
    }
   },
   "source": [
    "## 逻辑函数"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "**获取a和b元素匹配的位置。**\n",
    "- `a = np.array([1, 2, 3, 2, 3, 4, 3, 4, 5, 6])`\n",
    "- `b = np.array([7, 2, 10, 2, 7, 4, 9, 4, 9, 8])`\n",
    "\n",
    "【知识点：逻辑函数】\n",
    "- 如何得到两个数组元素匹配的位置？"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2020-09-06T02:53:59.537622Z",
     "start_time": "2020-09-06T02:53:59.531638Z"
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "(array([1, 3, 5, 7], dtype=int64),)\n",
      "(array([1, 3, 5, 7], dtype=int64),)\n"
     ]
    }
   ],
   "source": [
    "import numpy as np\n",
    "\n",
    "a = np.array([1, 2, 3, 2, 3, 4, 3, 4, 5, 6])\n",
    "b = np.array([7, 2, 10, 2, 7, 4, 9, 4, 9, 8])\n",
    "mask = np.equal(a, b)\n",
    "\n",
    "# 方法1\n",
    "x = np.where(mask)\n",
    "print(x)  # (array([1, 3, 5, 7], dtype=int64),)\n",
    "\n",
    "# 方法2\n",
    "x = np.nonzero(mask)\n",
    "print(x)  # (array([1, 3, 5, 7], dtype=int64),)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "ExecuteTime": {
     "end_time": "2020-09-06T02:54:19.320517Z",
     "start_time": "2020-09-06T02:54:19.315496Z"
    }
   },
   "source": [
    "**获取5到10 之间的所有元素。**\n",
    "- `a = np.array([2, 6, 1, 9, 10, 3, 27])`\n",
    "\n",
    "【知识点：逻辑函数】\n",
    "- 如何从numpy数组中提取给定范围内的所有元素？"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2020-09-06T02:55:11.162117Z",
     "start_time": "2020-09-06T02:55:11.156161Z"
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "[ 6  9 10]\n",
      "[ 6  9 10]\n",
      "[ 6  9 10]\n"
     ]
    }
   ],
   "source": [
    "import numpy as np\n",
    "\n",
    "a = np.array([2, 6, 1, 9, 10, 3, 27])\n",
    "mask = np.logical_and(np.greater_equal(a, 5), np.less_equal(a, 10))\n",
    "\n",
    "# 方法1\n",
    "x = np.where(mask)\n",
    "print(a[x])  # [ 6  9 10]\n",
    "\n",
    "# 方法2\n",
    "x = np.nonzero(mask)\n",
    "print(a[x])  # [ 6  9 10]\n",
    "\n",
    "# 方法3\n",
    "x = a[np.logical_and(a >= 5, a <= 10)]\n",
    "print(x)  # [ 6  9 10]"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "**对于两个随机数组A和B,检查他们是否相等**\n",
    "\n",
    "【知识点：逻辑函数】\n",
    "\n",
    "- (提示: np.allclose, np.array_equal)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2020-09-14T09:35:57.408576Z",
     "start_time": "2020-09-14T09:35:57.404623Z"
    }
   },
   "outputs": [],
   "source": [
    "A = np.random.randint(0,2,5)\n",
    "B = np.random.randint(0,2,5)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2020-09-14T09:35:58.285123Z",
     "start_time": "2020-09-14T09:35:58.280479Z"
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "False\n"
     ]
    }
   ],
   "source": [
    "\n",
    "# Assuming identical shape of the arrays and a tolerance for the comparison of values\n",
    "equal = np.allclose(A,B)\n",
    "print(equal)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "**何对布尔值取反，或者原位(in-place)改变浮点数的符号(sign)？**\n",
    "\n",
    "【知识点：逻辑函数】\n",
    "- (提示: np.logical_not, np.negative)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 13,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2020-09-14T14:05:59.290471Z",
     "start_time": "2020-09-14T14:05:59.284521Z"
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "[0 1]\n"
     ]
    },
    {
     "data": {
      "text/plain": [
       "array([1, 0])"
      ]
     },
     "execution_count": 13,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "Z = np.array([0,1])\n",
    "print(Z)\n",
    "np.logical_not(Z, out=Z)\n",
    "# Z = np.random.uniform(-1.0,1.0,100)\n",
    "\n",
    "# np.negative(Z, out=Z)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 14,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2020-09-14T14:08:05.101330Z",
     "start_time": "2020-09-14T14:08:05.096343Z"
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "[0.2  1.15]\n"
     ]
    },
    {
     "data": {
      "text/plain": [
       "array([-0.2 , -1.15])"
      ]
     },
     "execution_count": 14,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "Z = np.array([0.2,1.15])\n",
    "print(Z)\n",
    "np.negative(Z, out=Z)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "**找出数组中与给定值最接近的数**"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 10,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "[[0 1 2 3]\n",
      " [4 5 6 7]]\n",
      "5\n"
     ]
    }
   ],
   "source": [
    "Z=np.array([[0,1,2,3],[4,5,6,7]])\n",
    "print(Z)\n",
    "z=5.1\n",
    "np.abs(Z - z).argmin()\n",
    "print(Z.flat[np.abs(Z - z).argmin()])"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": []
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.6.10"
  },
  "toc": {
   "base_numbering": 1,
   "nav_menu": {},
   "number_sections": true,
   "sideBar": true,
   "skip_h1_title": false,
   "title_cell": "Table of Contents",
   "title_sidebar": "Contents",
   "toc_cell": false,
   "toc_position": {
    "height": "calc(100% - 180px)",
    "left": "10px",
    "top": "150px",
    "width": "224.2px"
   },
   "toc_section_display": true,
   "toc_window_display": true
  },
  "varInspector": {
   "cols": {
    "lenName": 16,
    "lenType": 16,
    "lenVar": 40
   },
   "kernels_config": {
    "python": {
     "delete_cmd_postfix": "",
     "delete_cmd_prefix": "del ",
     "library": "var_list.py",
     "varRefreshCmd": "print(var_dic_list())"
    },
    "r": {
     "delete_cmd_postfix": ") ",
     "delete_cmd_prefix": "rm(",
     "library": "var_list.r",
     "varRefreshCmd": "cat(var_dic_list()) "
    }
   },
   "types_to_exclude": [
    "module",
    "function",
    "builtin_function_or_method",
    "instance",
    "_Feature"
   ],
   "window_display": false
  }
 },
 "nbformat": 4,
 "nbformat_minor": 4
}
